#include "hllc.hpp"
#include "sweFunctions.hpp"
#include "geometry.hpp"
#include "reconstruction.hpp"

namespace hms {


template<typename MeshType>
template<ReconstructionType recType, bool atomicWrite>
void SWESolver<MeshType>::hllcScheme(
	const MeshBase<MeshType>& mesh, 
	Index e
){
	// using RT = ReconstructionType;
	static constexpr bool
		isUniMesh  { std::is_same_v<MeshType, UniMesh> },
		isRectMesh { std::is_same_v<MeshType, RectMesh> },
		isOrtho    { isUniMesh || isRectMesh };

	auto edge { mesh.edge(e) };

	Array2i lr { edge.cells() };

	/* if both cells are dry, no fluxes occur */
	if ( isDry()(0, lr).all() )
		return;

	auto getFieldVals = [&](const auto& field, const Array2i& cells){
		return field.values()(hms::all, cells);
	};

	/* get field values for z and d. also required later for slope source treatment */
	RowArray2s
		zCellLR { getFieldVals(z(), lr) },
		dCellLR { getFieldVals(d(), lr) };

	/* as long as the edge orientation is not set during edge traversal, 
	 * we need to make this runtime-to-compile-time condition switch */
	EdgeValues ev { [&](){
		if constexpr ( isOrtho ){
			using ER = EdgeRange;
			if ( isHorizontal( e, mesh.derived().size() ) )
				return reconstruction<recType, ER::horizontal>(
					mesh, edge, lr, zCellLR, dCellLR
				);
			else
				return reconstruction<recType, ER::vertical>(
					mesh, edge, lr, zCellLR, dCellLR
				);
		} else {
			return reconstruction<recType>(
				mesh, edge, lr, zCellLR, dCellLR
			);
		}
	}() };
		

	if ( (ev.dLR < minWaterDepth).all() )
		return;

	/* transformed velocities */
	ArrayNNs<2,2> vRotLR;
	
	for (int i{0}; i<2; ++i)
		vRotLR.col(i) = transformCoords(ev.vLR.col(i), edge);

	ArrayNNs<3,2> flux {
		hllc::hllcScheme<Type>( ev, vRotLR, edge.normal() )
	};

	/* the slope source term depends on cell centre values and is thus
	 * not equal for both sides of the edge */
	slopeSourceToFlux(
		flux, 
		ev.zLR, 
		ev.dLR, 
		ev.hLR, 
		zCellLR, 
		dCellLR, 
		edge
	);
	
	registerFlux<atomicWrite>(flux.col(0), flux.col(1), edge, lr, mesh);
}

} // end namespace


